package com.atguigu.crowd.mvc.handler;

import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.atguigu.crowd.entity.Sheng;
import com.atguigu.crowd.exception.DuplicateKeyshengNameException;
import com.atguigu.crowd.mapper.ShengMapper;
import com.atguigu.crowd.service.api.ShengService;
import com.atguigu.crowd.util.ResultEntity;
import com.github.pagehelper.PageInfo;

import java.util.List;

/**
 * 同步(探讨异步能共用吗？)-省份管理 的控制器类——主要是区分同步和异步能不能共用一个接口————经过实践，答案是【 不能 】最直接的一点异步要返回的是json数据，，同步返回的是一个jsp页面
 * @author L
 *
 */
@Controller
public class ShengHandler {

	@Autowired
	ShengService shengService;
	/**
	 * 分页展示数据方法
	 * @param keyword
	 * @param pageNum
	 * @param pageSize
	 * @param modelMap
	 * @return
	 */
	@RequestMapping("sheng/get/page.ht")
	public String shengGetPage(
			@RequestParam(value="keyword",defaultValue="") String keyword,
			@RequestParam(value="pageNum",defaultValue="1") Integer pageNum,
			@RequestParam(value="pageSize",defaultValue="5") Integer pageSize,
			ModelMap modelMap
			) {
		
			//调用service 方法获取 pageInfo对象
			PageInfo<Sheng>pageInfo =shengService.getPage(pageNum, pageSize, keyword);
			
			modelMap.addAttribute("pageInfo", pageInfo);
			
			return "sheng/sheng-page";
			
			//web同步开发的情况下 解决重复提交的问题（异步是没有这种情况的，只有同步才有）——使用重定向
			//【特别注意，重定向是不能直接指定页面的，只能指定接口】，所以要么写个接口跳转，这样太麻烦了，还是直接写在mvc:view-controller里面吧，所以这也许就是为什么ajax异步盛行的原因吧，异步不存在这个重复提交的问题
			//但是直接重定向，pageInfo 这个域对会丢失，挺麻烦，还必须写个接口方法，再存一下这个域对象,实验失败，暂时不解决
			//return "redirect:/sheng/sheng-page.ht";
			
			//为什么之前的登录而已实验这种方式，我猜想是因为登录后的页面不需要前页的任何数据，而这里要带数据
	}
	/**
	 * 解决重定向域数据丢失问题
	 */
	@RequestMapping("/sheng/sheng-page.ht")
	public String shengGetPage(ModelMap modelMap) {
		
		//试过了几种方式，暂时失败，先不管，以后再处理
			//modelMap.addAttribute("pageInfo", pageInfo);
			
			return "sheng/sheng-page";
	}
	/**
	 * 跳转到 查看
	 * @return
	 */
	@RequestMapping("sheng/to/view.ht")
	public String shengToView(@Param("id") Integer id,ModelMap modelMap) {
		
		//1、根据sheng省份的id查询到sheng省份对象
		Sheng sheng =shengService.getShengByPrimaryKey(id);
		
		System.out.println("----------id:---------"+id);
		
		//2、将sheng省份对象存入到ModelMap模型
		modelMap.addAttribute("sheng", sheng);
		return "sheng/sheng-view";//这个逻辑处理完之后，跳转到修改页面 admin-edit.jsp 
	}
	/**
	 * 【纯跳转】跳转到新增页面去，也可以在 view-controller-中直接维护，因为是纯页面跳转
	 */
	@RequestMapping("sheng/to/sheng-add.ht")
	public String shengToadd(){
		
		return "sheng/sheng-add";
	}
	/**
	 *  新增/保存省份 的 handler方法
	 */
	@RequestMapping("sheng/add/one.ht")
	public String shengAddOne(@Param("shengName") String shengName,ModelMap modelMap){
		
		System.out.println("测试参数对不对");
		System.out.println("shengName="+shengName);
		
		//保存前要判断一下省份不能重复，就好像账号不能重复一样 
		//这个其实可以用数据库的唯一约束，这样更省性能，就少写代码了，然后代码里面如果再处理一下的话，就是双重安全，万无一失
		
		//判断一下是否数据库里面已经有这个省份名了
		int existMessage=shengService.existShengNameCount(shengName);
		System.out.println("是否已经存在这个省份名称了："+existMessage+"------------------");
		//调用service方法获取PageInfo对象
		if (existMessage>0) {
			//说明已经存在相同的数据了
			//modelMap.addAttribute("existMessage", "已经存在'"+shengName+"'这个省份名称了,请添加不重复的省份名称");
			//return "forward:/sheng/to/sheng-add.ht";//重新回到新增页面，并且告诉页面，我们数据已经存在了,这里只能用转发，
			//不能用重定向，用重定向会报错(具体原因暂时还没搞清楚)，所以我们上面用了转发,其实我们还可以使用异常类处理这个需求
		}
		//上面的还有另外一种写法，就是异常类，我们暂时注释掉上面if里面的语句，直接就让他报错，使用异常类来处理看看,推荐使用异常类的方式，整体来说更加高级和优雅
		Logger logge = LoggerFactory.getLogger(ShengHandler.class);
		int result=0;
		try {
		//执行保存
		 result = shengService.shengAddOne(new Sheng(null, shengName));
		}catch(Exception e) {
			e.printStackTrace();
			System.out.println("---------------");
			logge.info("异常的全类名"+e.getClass().getName());
			
			if (e instanceof DuplicateKeyException) {
				throw new DuplicateKeyshengNameException("抱歉，省份重复了，保存失败，请重新输入一个不重复的省份名称");
			}
		}
		
		
		if (result>0) {
			System.out.println("新增成功！！！！！！！！！！！！！！！！！");
		}else {
			System.out.println("新增失败---------------------");
		}
		
		//新增完成之后就跟删除完之后一样，调回到对应的主页面来
		//return "forward:admin/to/main/page.ht";	//转发
		//return "redirect:/admin/to/main/page.ht";	//重定向
		return "redirect:/sheng/get/page.ht?pageNum="+Integer.MAX_VALUE;//新增数据完成后要保证返回的页面是最后一页，这样用户能够直观的看到新增的数据
	}
	/**
	 * 跳转到 修改/编辑 页面去，因为要做回显所以必须要这个方法来做一点事情
	 * @return
	 */
	@RequestMapping("sheng/to/edit.ht")
	public String adminToEdit(@Param("id") Integer id,ModelMap modelMap) {
		
		//1、根据sheng的id查询到sheng省份对象
		Sheng sheng =shengService.getShengByPrimaryKey(id);
		//2、将Sheng省份对象存入到ModelMap模型
		modelMap.addAttribute("sheng", sheng);
		return "sheng/sheng-edit";  //跳转到修改页面 admin-edit.jsp 
	}
	/**
	 * 执行修改
	 * @return
	 */
	@RequestMapping("sheng/do/edit.ht")
	public String shengDoEdit(Sheng sheng,@RequestParam("pageNum") Integer pageNum,@RequestParam("keyword") String keyword) {
		
		//异常处理：异常映射
		try {
			shengService.updateByExampleSelective(sheng);
		}
		catch(Exception e ){
			if (e instanceof DuplicateKeyException) {
				throw new DuplicateKeyshengNameException("抱歉，该省份已存在，修改失败");
			}
		}
		
		System.out.println("------pageNum:"+pageNum);
		System.out.println("------keyword:"+keyword);
		
		//return "admin/get/page.ht?pageNum="+pageNum+"&keyword="+keyword;
		return "redirect:/sheng/get/page.ht?pageNum="+pageNum+"&keyword="+keyword;
	}
	/**
	 * 删除的handler方法(思考一个问题，同步和异步能不能共用这个后端接口——我的猜测是可以，我们后面来验证一下)
	 * @param pageNum
	 * @param keyword
	 * @return
	 */
	@RequestMapping("sheng/delete/one/{id}/{pageNum}/{keyword}.ht")
	public String adminDeleteOne(
			@PathVariable("id") Integer id,
			@PathVariable("pageNum") Integer pageNum,
			@PathVariable("keyword") String keyword
			){
		
		System.out.println("-----------shengId:"+id);
		//调用service方法获取PageInfo对象
		shengService.deleteById(id);
		
		/*尝试方案1：直接转发到sheng-page.jsp会无法显示分页数据*/
		/*return "sheng-page";*/
		
		//方案2：转发到admin-page的 @RequestMapping地址 即  sheng/get/page.ht
		//return "forward:/sheng/get/page.ht";
		
		//方案3：重定向，终极武器，重定向能够解决很多问题
		//return "redirect:/sheng/get/page.ht"; //不带参数，只是删除后不会保持删除后的状态又回到了第1页
		
		System.out.println("-----------pageNum:"+pageNum);
		System.out.println("-----------keyword:"+keyword);
		return "redirect:/sheng/get/page.ht?pageNum="+pageNum+"&keyword="+keyword;
	}
	
	//----下面都是【异步专用】的方法（注意：同步的接口不能完全和异步通用（service和dao/mapper可以，主要是控制器handler不能通用，返回类型不一样，同步返回的基本上String类型，返回的是jsp（路径）页面），异步返回的基本上JSON数据，数据类型不限制，你也可以做统一数据类型处理
	/**
	 * 【异步专用】跳转到异步分页对的主页面
	 */
	
	@RequestMapping("shengAjax/to/page.ht")
	public String shengAjaxtoPage() {
		
		return "/shengAjax/sheng-page";
	}
	/**
	 * 【异步专用】分页展示数据方法-这里还统一了返回类型，方便前端使用所以正常情况下，控制器里面的接口异步开发和同步开发还是有区别的，返回的数据类型是最大的区别，虽然大体逻辑是差不多的，但是详细过程是有区别的，代码是一个极其严谨的过程，所以，一般异步的接口和同步的接口我个人建议分开来写，避免出现问题
	 * @param keyword
	 * @param pageNum
	 * @param pageSize
	 * @param modelMap
	 * @return
	 */
	@ResponseBody
	@RequestMapping("shengAjax/get/page.ht")
	public ResultEntity<PageInfo<Sheng>> shengAjaxGetPage(
			@RequestParam(value="keyword",defaultValue="") String keyword,
			@RequestParam(value="pageNum",defaultValue="1") Integer pageNum,
			@RequestParam(value="pageSize",defaultValue="5") Integer pageSize,
			ModelMap modelMap
			) {
		
			//调用service 方法获取 pageInfo对象
			PageInfo<Sheng>pageInfo =shengService.getPage(pageNum, pageSize, keyword);
	
			//modelMap.addAttribute("pageInfo", pageInfo);//实际上异步并不需要存到域里面了，而是直接通过Ajax就可以传递任何数据，当然这个域也可以保留，作为辅助传递数据，我们这里是等于测试一下，看看这个域能不能生效
			modelMap.addAttribute("test", "我测试一下，看看异步情况下域能不能传值到前端页面去");
			
			return ResultEntity.successWithData(pageInfo);
			
			//web同步开发的情况下 解决重复提交的问题（异步是没有这种情况的，只有同步才有）——使用重定向
			//【特别注意，重定向是不能直接指定页面的，只能指定接口】，所以要么写个接口跳转，这样太麻烦了，还是直接写在mvc:view-controller里面吧，所以这也许就是为什么ajax异步盛行的原因吧，异步不存在这个重复提交的问题
			//但是直接重定向，pageInfo 这个域对会丢失，挺麻烦，还必须写个接口方法，再存一下这个域对象,实验失败，暂时不解决
			//return "redirect:/sheng/sheng-page.ht";
			
			//为什么之前的登录而已实验这种方式，我猜想是因为登录后的页面不需要前页的任何数据，而这里要带数据
	}
	/**
	 * 异步专用   新增/保存省份
	 * @return
	 */
	@RequestMapping("/Sheng/do/save.ht")
	@ResponseBody
	public ResultEntity<Sheng> ShengDoSave(Sheng sheng){
		
		//因为这里我们数据库里面做了处理的，省份做了唯一约束，所以这里我们有两种处理方式，一种是捕获一下异常，一种的判断一下是否重复，很明显我们这里捕获一下异常刚合适一些
		
		try {
			shengService.shengAddOne(sheng);//service接口和dao/Mapper接口是可以共用的
		} catch (Exception e) {
			
			return ResultEntity.failed("可能是省份重复了具体信息如下："+e);
		}
		
		return ResultEntity.successWithoutData();
	}
	/**
	 * 异步专用-更新
	 * @return
	 */
	@ResponseBody
	@RequestMapping("sheng/update.ht")
	public ResultEntity<String> ShengUpdate(@RequestBody Sheng sheng){
		
		//这里不用@RequestBody的话，根本接不到Ajax异步传过来的参数
		shengService.updateSheng(sheng);
		return ResultEntity.successWithoutData();
	}

	/**
	 * 单条删除和批量删除的接口
	 * @return
	 */
	@ResponseBody
	@RequestMapping("remove/by/Sheng/id/array.ht")
	public ResultEntity<String>RemoveByShengIdArray(@RequestBody List<Integer>idsList){

		shengService.removeShengs(idsList);

		return ResultEntity.successWithoutData();
	}
}






















